﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.NPOIHelp
{
    public class 文字表
    {
        public 文字表(string tableLines)
        {
            this._文字表源文本 = tableLines;
            解析文字表();
            增补文字表虚单元格();
        }

        private string _文字表源文本;

        public string 文字表源文本
        {
            get { return _文字表源文本; }
        }

        private int _最大单元格数;

        public int 最大单元格数
        {
            get { return _最大单元格数; }
        }

        public void 解析文字表()
        {
            // 在此处解析各行
            if (string.IsNullOrWhiteSpace(_文字表源文本))
            {
                _文字表行集 = null;
                return;
            }

            var lines = _文字表源文本.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length <= 0)
            {
                _文字表行集 = null;
                return;
            }

            if (_文字表行集 == null)
                _文字表行集 = new List<文字表行>();

            if (_文字表行集.Count > 0)
                _文字表行集.Clear();

            var colAlignDefIndex = -1;

            for (int i = 0; i < lines.Length; i++)
            {
                var line = lines[i];

                if (string.IsNullOrWhiteSpace(line)) continue;

                // 二维文字表标题行下的装饰分隔行也添加，不然索引会出错！
                // if (CustomMarkdownSupport.IsTableCaptionSplittor(line)) continue;

                var row = new 文字表行(line);
                row.解析文字表行();

                if (i == 0 && row.行内实单元格数 == 1)
                {
                    row.置是否文字表标题(true);
                }

                _文字表行集.Add(row);

                if (row.是否列定义)
                {
                    colAlignDefIndex = i;
                }
            }

            if (colAlignDefIndex < 0)
            {
                // 没有列定义行
                // 标题行为空、表头行集为空、列定义行为空，只有表体行集
                if (_文字表行集 != null && _文字表行集.Count > 0)
                {
                    _文字表标题行 = null;
                    _文字表头行集 = null;
                    _文字表列定义行 = null;

                    if (_文字表体行集 == null)
                        _文字表体行集 = new List<文字表行>();
                    if (_文字表体行集.Count > 0)
                        _文字表体行集.Clear();

                    foreach (var row in _文字表行集)
                    {
                        if (row.是否文字表标题装饰行) continue;  // 这里不要考虑标题的问题

                        _文字表体行集.Add(row);
                    }
                }
            }
            else if (colAlignDefIndex == 0)
            {
                // 首行是列定义行
                // 标题行为空、表头行集为空、列定义行为首行，只有表体行集
                if (_文字表行集 != null && _文字表行集.Count > 0)
                {
                    _文字表标题行 = null;
                    _文字表头行集 = null;
                    _文字表列定义行 = _文字表行集[0];

                    if (_文字表行集.Count > 1)
                    {
                        if (_文字表体行集 == null)
                            _文字表体行集 = new List<文字表行>();
                        if (_文字表体行集.Count > 0)
                            _文字表体行集.Clear();

                        for (int i = 1; i < _文字表行集.Count; i++)
                        {
                            var row = _文字表行集[i];
                            if (row.是否文字表标题装饰行) continue;  // 这里不要考虑标题的问题

                            _文字表体行集.Add(row);
                        }
                    }
                    else
                    {
                        _文字表体行集 = null;
                    }
                }
            }
            else
            {
                // 有至少一行表头行或标题行

                if (_文字表行集 != null && _文字表行集.Count > 0)
                {
                    var fstRow = _文字表行集[0];
                    if (fstRow.是否文字表标题)
                    {
                        // 首行标题行
                        _文字表标题行 = fstRow;
                        var headRowsCount = colAlignDefIndex - 1;
                        if (headRowsCount > 0)
                        {
                            if (_文字表头行集 == null)
                                _文字表头行集 = new List<文字表行>();
                            if (_文字表头行集.Count > 0)
                                _文字表头行集.Clear();

                            for (int i = 1; i < colAlignDefIndex; i++)
                            {
                                var row = _文字表行集[i];
                                if (row.是否文字表标题 || row.是否文字表标题装饰行) continue;
                                // 只有这里有可能出现标题行！

                                _文字表头行集.Add(row.置是否文字表表头行(true));
                            }
                        }
                        else { _文字表头行集 = null; }

                        _文字表列定义行 = _文字表行集[colAlignDefIndex];

                        var bodyRowsCount = _文字表行集.Count - 1 - colAlignDefIndex;
                        if (bodyRowsCount > 0)
                        {
                            if (_文字表体行集 == null)
                                _文字表体行集 = new List<文字表行>();
                            if (_文字表体行集.Count > 0)
                                _文字表体行集.Clear();

                            for (int i = colAlignDefIndex + 1; i < _文字表行集.Count; i++)
                            {
                                var row = _文字表行集[i];
                                if (row.是否文字表标题装饰行) continue;  // 这里即使只有一格也不视为标题

                                _文字表体行集.Add(row);
                            }
                        }
                        else { _文字表体行集 = null; }
                    }
                    else
                    {
                        // 无标题，首行即是表头行
                        _文字表标题行 = null;

                        var headRowsCount = colAlignDefIndex;
                        if (headRowsCount > 0)
                        {
                            if (_文字表头行集 == null)
                                _文字表头行集 = new List<文字表行>();
                            if (_文字表头行集.Count > 0)
                                _文字表头行集.Clear();

                            for (int i = 0; i < colAlignDefIndex; i++)
                            {
                                var row = _文字表行集[i];
                                if (row.是否文字表标题装饰行) continue;  // 这里没有标题

                                _文字表头行集.Add(row);
                            }
                        }
                        else { _文字表头行集 = null; }

                        _文字表列定义行 = _文字表行集[colAlignDefIndex];

                        var bodyRowsCount = _文字表行集.Count - 1 - colAlignDefIndex;
                        if (bodyRowsCount > 0)
                        {
                            if (_文字表体行集 == null)
                                _文字表体行集 = new List<文字表行>();
                            if (_文字表体行集.Count > 0)
                                _文字表体行集.Clear();

                            for (int i = colAlignDefIndex + 1; i < _文字表行集.Count; i++)
                            {
                                var row = _文字表行集[i];
                                if (row.是否文字表标题装饰行) continue;  // 这里即使一格也不视为标题

                                _文字表体行集.Add(row);
                            }
                        }
                        else { _文字表体行集 = null; }
                    }
                }
            }

            int maxColumns = 0;
            foreach (var row in _文字表行集)
            {
                maxColumns = Math.Max(maxColumns, row.行内实单元格数);
            }
            _最大单元格数 = maxColumns;
        }

        private List<文字表行> _文字表行集 = null;

        public List<文字表行> 文字表行集
        {
            get
            {
                return _文字表行集;
            }
        }

        private 文字表行 _文字表标题行 = null;

        public 文字表行 文字表标题行
        {
            get { return _文字表标题行; }
        }

        private List<文字表行> _文字表头行集 = null;

        public List<文字表行> 文字表头行集
        {
            get { return _文字表头行集; }
        }

        private 文字表行 _文字表列定义行 = null;

        public 文字表行 文字表列定义行
        {
            get { return _文字表列定义行; }
        }

        private List<文字表行> _文字表体行集 = null;

        public List<文字表行> 文字表体行集
        {
            get { return _文字表体行集; }
        }

        public string 文字表标题文本
        {
            get
            {
                if (_文字表标题行 == null) return null;

                return _文字表标题行.文字表行标题文本;
            }
        }

        public int 文字表实际行数
        {
            get
            {
                var realRowCount = 0;
                if (this.文字表标题行 != null) realRowCount++;
                if (this.文字表头行集 != null && this.文字表头行集.Count > 0) realRowCount += this.文字表头行集.Count;
                if (this.文字表体行集 != null && this.文字表体行集.Count > 0) realRowCount += this.文字表体行集.Count;
                return realRowCount;
            }
        }

        public void 增补文字表虚单元格()
        {
            if (this._文字表列定义行 == null)
            {
                // 直接按最大列数补全

                if (_文字表体行集 != null && _文字表体行集.Count > 0)
                {
                    for (int i = 0; i < _文字表体行集.Count; i++)
                    {
                        // 表体行集中不包括标题行、标题装饰行、列定义行
                        var row = _文字表体行集[i];
                        if (row.行内实单元格数 < this.最大单元格数)
                        {
                            for (int j = 1; j <= this.最大单元格数 - row.行内实单元格数; j++)
                            {
                                row.文字表单元格集.Add(new 文字表单元格("", false, true));
                            }
                        }
                    }
                }

                // 此种情形下不必考虑列定义行、标题行、表头行集
            }
            else
            {
                // 既要考虑最大列数，也要考虑单元格对齐方式

                // 先补全列定义行
                var vcount = this.最大单元格数 - this._文字表列定义行.行内实单元格数;
                for (int i = 0; i < vcount; i++)
                {
                    var newCell = new 文字表单元格("-", true, true);   // 默认左对齐，首尾都不需要冒号
                    this._文字表列定义行.文字表单元格集.Add(newCell);
                }

                // 补全表头（不含标题行、列定义行、标题装饰行、表体行）
                if (_文字表头行集 != null && _文字表头行集.Count > 0)
                {
                    for (int i = 0; i < _文字表头行集.Count; i++)
                    {
                        var row = _文字表头行集[i];
                        for (int j = 1; j <= this.最大单元格数 - row.行内实单元格数; j++)
                        {
                            row.文字表单元格集.Add(new 文字表单元格("", false, true).置文字表单元格对齐(文字表单元格对齐.居中对齐));
                        }

                        // 表头总是居中对齐，所以不用下面这个设置对齐方式！
                        //for (int j = this.最大单元格数; j <= this.最大单元格数; j++)
                        //{
                        //    var cell = row.文字表单元格集[j - 1];
                        //    cell.置文字表单元格对齐(this._文字表列定义行.文字表单元格集[j - 1].文字表单元格对齐);
                        //}
                    }
                }

                // 补全表体（不含标题行、列定义行、标题装饰行、表头行）
                if (_文字表体行集 != null && _文字表体行集.Count > 0)
                {
                    for (int i = 0; i < _文字表体行集.Count; i++)
                    {
                        var row = _文字表体行集[i];
                        for (int j = 1; j <= this.最大单元格数 - row.行内实单元格数; j++)
                        {
                            row.文字表单元格集.Add(new 文字表单元格("", false, true));
                        }

                        // 表体单元格受列定义行中定义的各列对齐方式的限制，所以用下面的方式！
                        for (int j = this.最大单元格数; j <= this.最大单元格数; j++)
                        {
                            var cell = row.文字表单元格集[j - 1];
                            cell.置文字表单元格对齐(this._文字表列定义行.文字表单元格集[j - 1].文字表单元格对齐);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 取表头最后一行、列定义行、根据指定表体行索引获得的对应表体行拼接成一个新文字表返回。
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <returns></returns>
        public 文字表 记录行到文字表(int rowIndex)
        {
            if (this._文字表体行集 == null || this._文字表体行集.Count <= 0) return null;
            if (this._文字表头行集 == null || this._文字表头行集.Count == 0) return null;
            if (this._文字表列定义行 == null) return null;

            if (rowIndex < 0 || rowIndex >= this._文字表体行集.Count) return null;

            var sb = new StringBuilder();
            sb.AppendLine(this._文字表头行集[this._文字表头行集.Count - 1].文字表行源文本);
            sb.AppendLine(this._文字表列定义行.文字表行源文本);
            sb.AppendLine(this._文字表体行集[rowIndex].文字表行源文本);

            return new 文字表(sb.ToString());
        }

        /// <summary>
        /// 将此实例取表头最后一行、所有数据行转换为一个文本数据表类的实例。
        /// </summary>
        /// <returns></returns>
        public 文本数据表 到文本数据表()
        {
            if (this._文字表体行集 == null || this._文字表体行集.Count <= 0)
                throw new Exception("此文字表没有表体数据行，无法转换。");

            string[][] dataArray;

            if (this._文字表头行集 != null && this._文字表头行集.Count > 0)
            {
                dataArray = new string[this._文字表体行集.Count + 1][];
                var fieldCells = this._文字表头行集[this._文字表头行集.Count - 1].文字表单元格集;
                var fieldArray = new string[fieldCells.Count];
                for (int i = 0; i < fieldCells.Count; i++)
                {
                    fieldArray[i] = fieldCells[i].文字表单元格文本;
                }
                dataArray[0] = fieldArray;

                for (int j = 0; j < this._文字表体行集.Count; j++)
                {
                    var rowCells = this._文字表体行集[j].文字表单元格集;
                    var rowArray = new string[rowCells.Count];
                    for (int k = 0; k < rowCells.Count; k++)
                    {
                        rowArray[k] = rowCells[k].文字表单元格文本;
                    }
                    dataArray[j + 1] = rowArray;
                }

                return new 文本数据表(dataArray, true);
            }
            else
            {
                dataArray = new string[this._文字表体行集.Count][];
                for (int j = 0; j < this._文字表体行集.Count; j++)
                {
                    var rowCells = this._文字表体行集[j].文字表单元格集;
                    var rowArray = new string[rowCells.Count];
                    for (int k = 0; k < rowCells.Count; k++)
                    {
                        rowArray[k] = rowCells[k].文字表单元格文本;
                    }
                    dataArray[j] = rowArray;
                }

                return new 文本数据表(dataArray, false);
            }
        }
    }

    public class 文字表行
    {
        public 文字表行(string lineText)
        {
            this._文字表行源文本 = lineText;

            // 解析文字表行();  // 需要一次遍历后才能确定第2参数，不适合自动调用
        }

        private string _文字表行源文本;

        public string 文字表行源文本
        {
            get { return _文字表行源文本; }
        }

        private int _行内实单元格数;

        public int 行内实单元格数
        {
            get { return _行内实单元格数; }
            set { _行内实单元格数 = value; }
        }

        public int 行内总单元格数
        {
            get
            {
                if (_文字表单元格集 == null) return 0;

                return _文字表单元格集.Count;
            }
        }

        public int 行内虚单元格数
        {
            get { return 行内总单元格数 - 行内实单元格数; }
        }

        /// <summary>
        /// 本方法必须手动调用！！！
        /// </summary>
        public void 解析文字表行()
        {
            // 在此处解析文字表行
            if (string.IsNullOrWhiteSpace(_文字表行源文本))
            {
                _文字表单元格集 = null;
                return;
            }

            var tmpText = _文字表行源文本.Trim(new char[] { ' ', '　', '\t' });
            if (tmpText.StartsWith("|") || tmpText.StartsWith("｜"))
            {
                tmpText = tmpText.Substring(1);
            }

            if (tmpText.EndsWith("|") || tmpText.EndsWith("｜"))
            {
                tmpText = tmpText.Substring(0, tmpText.Length - 1);
            }

            var spans = tmpText.Split(new char[] { '|', '｜' }, StringSplitOptions.None);
            if (spans.Length <= 0)
            {
                _文字表单元格集 = null;
                return;
            }
            _行内实单元格数 = spans.Length;

            if (CustomMarkdownSupport.IsTableCaptionSplittor(_文字表行源文本))
            {
                _文字表单元格集 = null;
                this._是否文字表标题装饰行 = true;
                return;
            }

            if (_文字表单元格集 == null)
            {
                _文字表单元格集 = new List<文字表单元格>();
            }

            if (_文字表单元格集.Count > 0)
            {
                _文字表单元格集.Clear();
            }

            foreach (var span in spans)
            {
                _文字表单元格集.Add(new 文字表单元格(span, _是否列定义));
                // 单元格在构造时，会自动解析列定义中的对齐方式信息。
            }

            if (CustomMarkdownSupport.IsColumnAlignmentDefinitionLine(_文字表行源文本))
            {
                this._是否列定义 = true;
            }

            for (int i = 0; i < _文字表单元格集.Count; i++)
            {
                var cell = _文字表单元格集[i];
                if (cell.是否被合并) continue;

                if (cell.是否合并单元格 && cell.合并格数 > 0)
                {
                    for (int j = i + 1; j <= Math.Min(_文字表单元格集.Count - 1, i + cell.合并格数); j++)
                    {
                        var overedCell = _文字表单元格集[j];
                        overedCell.置是否被合并(true);
                    }
                }
            }
        }

        private List<文字表单元格> _文字表单元格集 = new List<文字表单元格>();

        public List<文字表单元格> 文字表单元格集
        {
            get
            {
                return _文字表单元格集;
            }
        }

        private bool _是否列定义 = false;

        public bool 是否列定义
        {
            get { return _是否列定义; }
        }

        private bool _是否文字表标题 = false;

        public bool 是否文字表标题
        {
            get { return _是否文字表标题; }
        }

        private bool _是否文字表标题装饰行 = false;
        /// <summary>
        /// 标题行下面的装饰行。类似：
        /// |================|
        /// </summary>
        public bool 是否文字表标题装饰行
        {
            get { return _是否文字表标题装饰行; }
        }

        public 文字表行 置是否文字表标题(bool isTitle)
        {
            _是否文字表标题 = isTitle;
            return this;
        }

        public string 文字表行标题文本
        {
            get
            {
                if (_是否文字表标题 == false) return null;

                if (_文字表单元格集 != null && _文字表单元格集.Count > 0)
                {
                    return _文字表单元格集[0].文字表单元格文本;
                }

                return null;
            }
        }

        private bool _是否文字表表头行 = false;

        public bool 是否文字表表头行
        {
            get { return _是否文字表表头行; }
        }

        public 文字表行 置是否文字表表头行(bool isHeadRow)
        {
            this._是否文字表表头行 = isHeadRow;
            if (this.文字表单元格集 != null && this.文字表单元格集.Count > 0)
            {
                foreach (var cell in this.文字表单元格集)
                {
                    cell.置文字表单元格对齐(文字表单元格对齐.居中对齐);  // 表头总是居中对齐的
                }
            }
            return this;
        }
    }

    public class 文字表单元格
    {
        public 文字表单元格(string text, bool isColumnAlignmentDefinition, bool isVirtualCell = false)
        {
            _文字表单元格源文本 = text;
            _是否列定义 = isColumnAlignmentDefinition;
            _是否虚单元格 = isVirtualCell;

            解析文字表单元格();
        }

        private string _文字表单元格源文本;

        public string 文字表单元格源文本
        {
            get { return _文字表单元格文本; }
        }

        public void 解析文字表单元格()
        {
            // 在此处解析文字表单元格

            // 搞清楚向右合并几个单元格。
            var regex = new Regex(@"(?<=(\-))[>]{1,}(?=[ 　\t]*$)");
            var match = regex.Match(_文字表单元格源文本);
            if (match.Success)
            {
                _是否合并单元格 = true;
                _合并格数 = match.Length;
            }
            else
            {
                _是否合并单元格 = false;
                _合并格数 = 0;
            }

            if (_是否列定义)
            {
                var cellText = _文字表单元格源文本.Trim(new char[] { ' ', '　', '\t', });
                var left = cellText.StartsWith(":") || cellText.StartsWith("：");
                var right = cellText.EndsWith(":") || cellText.EndsWith("：");

                if (left && right)
                {
                    _文字表单元格对齐 = 文字表单元格对齐.居中对齐;
                }
                else
                {
                    if (left)
                    {
                        _文字表单元格对齐 = 文字表单元格对齐.左对齐;
                    }
                    else
                    {
                        if (right)
                        {
                            _文字表单元格对齐 = 文字表单元格对齐.右对齐;
                        }
                        else
                        {
                            _文字表单元格对齐 = 文字表单元格对齐.左对齐;  // 默认为左对齐
                        }
                    }
                }

                _文字表单元格文本 = _文字表单元格源文本.Trim(new char[] { ' ', '　', '\t', ':', '：' })
                    .TrimEnd(new char[] { ' ', '　', '\t', '-', '>' });

                if (_文字表单元格文本.StartsWith("^") || _文字表单元格文本.EndsWith("^"))
                {
                    _是否自动编号列 = true;
                    _文字表单元格文本 = _文字表单元格文本.Trim(new char[] { ' ', '　', '\t', ':', '：', '-', '>', '^' });
                }
                else
                {
                    _是否自动编号列 = false;
                }
            }
            else
            {
                _文字表单元格文本 = _文字表单元格源文本.Trim(new char[] { ' ', '　', '\t' })
                    .TrimEnd(new char[] { ' ', '　', '\t', '-', '>' });
            }
        }

        private 文字表单元格对齐 _文字表单元格对齐 = 文字表单元格对齐.左对齐;  // 默认为左对齐

        public 文字表单元格对齐 文字表单元格对齐
        {
            get { return _文字表单元格对齐; }
        }

        public 文字表单元格 置文字表单元格对齐(文字表单元格对齐 align)
        {
            this._文字表单元格对齐 = align;
            return this;
        }

        private string _文字表单元格文本;

        public string 文字表单元格文本
        {
            get { return _文字表单元格文本; }
        }

        private int _合并格数 = 0;

        public int 合并格数
        {
            get { return _合并格数; }
        }

        public 文字表单元格 置合并格数(int count)
        {
            _合并格数 = count;
            return this;
        }

        private bool _是否合并单元格 = false;
        /// <summary>
        /// 只支持向右合并单元格。
        /// </summary>
        public bool 是否合并单元格
        {
            get { return _是否合并单元格; }
        }

        public bool _是否被合并 = false;

        /// <summary>
        /// 如此属性为真，此单元格不能合并右侧其它单元格。
        /// </summary>
        public bool 是否被合并
        {
            get { return _是否被合并; }
        }

        private bool _是否自动编号列 = false;

        public bool 是否自动编号列
        {
            get { return _是否自动编号列; }
        }

        public 文字表单元格 置是否自动编号列(bool autoNumber)
        {
            if (_是否列定义 == false) return this; // 只有列定义行才应支持设置此属性。

            _是否自动编号列 = autoNumber;
            return this;
        }

        public 文字表单元格 置是否被合并(bool beOvered)
        {
            _是否被合并 = beOvered;
            if (_是否被合并)
            {
                // 本身被合并的单元格，不能再重复指定合并其它单元格
                _是否合并单元格 = false;
                _合并格数 = 0;
            }
            return this;
        }

        private bool _是否列定义 = false;

        public bool 是否列定义
        {
            get { return _是否列定义; }
        }

        private bool _是否虚单元格 = false;

        public bool 是否虚单元格
        {
            get { return _是否虚单元格; }
        }
    }

    public enum 文字表单元格对齐
    {
        普通文本,
        左对齐,
        居中对齐,
        右对齐,
    }
}
